package com.newflypig.jblog.dao.hibernate;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import com.newflypig.jblog.dao.IArticleDAO;
import com.newflypig.jblog.model.Article;
import com.newflypig.jblog.model.BlogConfig;

@SuppressWarnings({ "unchecked", })
@Repository("articleDao")
public class ArticleDAOImpl extends BaseHibernateDAO<Article> implements IArticleDAO{
	// property constants
	public static final String TEXT = "text";
	public static final String TITLE = "title";
	public static final String RATE = "rate";
	public static final String SUPPORT = "support";
	public static final String AGAINST = "against";
	
	public List<Article> findAllDesc() {
		try {
			String queryString = "from Article order by createDate desc";
			Query queryObject = getSession().createQuery(queryString);
			List<Article> list=(List<Article>)queryObject.list();
			if(list.size()!=0)
				log.info("Find All Article objects order by articleId desc");
			else
				log.info("Find none Article object");
			return list;
		} catch (RuntimeException re) {
			log.error("Occur an Error when try to Find All Article objects", re);
			throw re;
		}
	}
	
	@Override
	public Article findById(Integer id) {
		try{
			//读取文章的基本数据字段
			String hql = "from Article a where a.articleId=:id";
			Query query=this.getSession().createQuery(hql).setInteger("id", id);
			Article article=(Article) query.uniqueResult();
			
			return article;
		}catch(RuntimeException re){
			log.error("Occer an Error when try to Find an Article Object,it's Id="+id);
			re.printStackTrace();
			throw re;
		}
	}

	@Override
	public void deleteById(Integer articleId) {
		this.setState(articleId, Article.STATE_DELETE);
	}

	@Override
	public void deleteForeverById(Integer articleId) {
		String sql = "delete from jblog2.jblog_article where id = :articleId";
		this.getSession().createSQLQuery(sql).setInteger("articleId", articleId).executeUpdate();
	}

	@Override
	public void ratePP(Integer articleId) {
		String sql = "update jblog2.jblog_article a set a.rate = a.rate + 1 where a.id = :articleId";
		this.getSession().createSQLQuery(sql).setInteger("articleId", articleId).executeUpdate();
	}
	
	/**
	 * 重写update函数，只更新部分关键字段
	 */
	@Override
	public void update(Article article) {
		String hql = "update Article a "
					+ "set a.markdown = :markdown "
					+ ", a.html = :html "
					+ ", a.title = :title "
					+ ", a.lastEditDate = now() "
					+ ", a.state = :state"
					+ (StringUtils.isEmpty(article.getUrlName()) ? "" : ", a.urlName = :urlName ")
					+ ", a.showInList = :showInList"
					+ " where a.articleId = :articleId ";
		
		Query query = this.getSession().createQuery(hql)
			.setString("markdown", article.getMarkdown())
			.setString("html", article.getHtml())
			.setString("title", article.getTitle())
			.setShort("state", article.getState())
			.setBoolean("showInList", article.getShowInList())
			.setInteger("articleId", article.getArticleId());
		
		if(!StringUtils.isEmpty(article.getUrlName()))
			query.setString("urlName", article.getUrlName());
			
		query.executeUpdate();
		
		this.cleanMenuConnects(article.getArticleId());
		
		this.buildMenuConnects(article);
	}
	
	/**
	 * 重构Menu关系
	 * @param article
	 */
	private void buildMenuConnects(Article article) {
		article.getMenus().forEach(menu -> {
			String sql = "insert into jblog2.jblog_menu_article(jblog_menu_id,jblog_article_id) values(:menuId,:articleId)";
			this.getSession().createSQLQuery(sql)
				.setInteger("menuId", menu.getId())
				.setInteger("articleId", article.getArticleId())
				.executeUpdate();
		});
	}

	/**
	 * 清除Menu关系
	 * @param articleId
	 */
	private void cleanMenuConnects(Integer articleId) {
		String sql = "delete from jblog2.jblog_menu_article where jblog_article_id = :articleId";
		
		this.getSession().createSQLQuery(sql).setInteger("articleId", articleId).executeUpdate();
	}
	
	@Override
	public void setState(Integer articleId, Short state) {
		this.log.info("begin to update state to " + state);
		String hql = "update Article a set a.state = :state where a.articleId = :articleId";
		int result = this.getSession().createQuery(hql)
			.setInteger("articleId", articleId)
			.setShort("state", state)
			.executeUpdate();
		this.log.info(result + " row accepted.update state to " + state);
	}

	@Override
	public void callNoResultableProc(String procName) {
		String sql = "call " + procName +"();";
		this.getSession().createSQLQuery(sql).executeUpdate();
	}

	@Override
	public List<Article> findForRSS(DetachedCriteria dc) {
		return dc.getExecutableCriteria(this.getSession())
			.setFirstResult(0)
			.setMaxResults(BlogConfig.RSS_COUNT)
			.list();
	}

	@Override
	public void exchangeIndex(Integer theId, Integer otherId) {
		String hql = "select a.index from Article a where a.articleId = :theId";
		Integer theIndex = (Integer) this.getSession().createQuery(hql).setInteger("theId", theId).uniqueResult();
		
		hql = "select a.index from Article a where a.articleId = :otherId";
		Integer otherIndex = (Integer) this.getSession().createQuery(hql).setInteger("otherId", otherId).uniqueResult();
		
		hql = "update Article set index = :index where articleId = :theId";
		this.getSession().createQuery(hql)
			.setInteger("index", otherIndex)
			.setInteger("theId", theId)
			.executeUpdate();
		
		hql = "update Article set index = :index where articleId = :otherId";
		this.getSession().createQuery(hql)
			.setInteger("index", theIndex)
			.setInteger("otherId", otherId)
			.executeUpdate();
	}

	@Override
	public void updateIndex(Integer articleId) {
		String hql = "update Article a set a.index = a.id where a.id = :articleId";
		this.getSession().createQuery(hql).setInteger("articleId", articleId).executeUpdate();
	}
}